<?php
/**
 * ELEMENT UI Upload 公共组件
 * User: apple
 * Date: 1/23/22
 * Time: 9:54 PM
 * todo: ELEMENT UI 上传组件属性[element-loading-spinner]无法刷新(这是element ui的BUG)
 */

/* @var $this yii\web\View */
/* @var $_params_ array 总参数变量 */
/* @var $column string [VUE]中字段名称 */
/* @var $ref string 自定义[ref]名称(遇到多图同一个字段，需自定义此变量切不可重复) */
/* @var $scenario array 图片上传场景 */
/* @var $uploadNum array 上传图数量，默认一张 */
/* @var $canMultiple array 是否可多选上传 */
/* @var $fileTypes array 允许的文件类型 */
/* @var $fileSize int 允许的文件大小, 单位：m */
/* @var $uploadUrlKey string 文件上传连接API, 参考：web/js/backend/setting.js中_url键值下 */
/* @var $wrapperClass string 外部容器样式名 */
/* @var $status bool 上传组件状态 */
/* @var $disabled bool 是否禁用上传组件 */

$componentBaseName = 'uploader';
### 组件ID - 防止重复
if (empty($this->params['uploader']['id'])) {
    $this->params['uploader']['id'] = \app\service\tool\GenerateService::newMongoId();
}
$id = $this->params['uploader']['id'];
// 组件名称
$componentName = $componentBaseName . '_' . $id;

### 组件ref
if (empty($ref)) {
    // 后扩展名
    $pattern = '/[a-z|A-Z|0-9|\_]*/u';
    preg_match_all($pattern, $column, $result);
    $ref = $componentBaseName . '_' . implode('_', array_filter($result[0]));
}

### 上传图数量
$uploadNum = empty($uploadNum) ? 1 : $uploadNum;
// 是否可多选上传，默认：只是一张图就没必要啦
$canMultiple = empty($canMultiple) ? $uploadNum > 1 : $canMultiple;
$canMultiple = $canMultiple ? 'true' : 'false';

### 文件上传连接键
$uploadUrlKey = empty($uploadUrlKey) ? 'upload' : $uploadUrlKey;

### 允许的文件类型
// 空的默认图片
$fileTypes = empty($fileTypes) ? ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'] : $fileTypes;
$fileTypes = !is_array($fileTypes) ? [$fileTypes] : $fileTypes;
$fileTypes = "['" . implode("', '", $fileTypes) . "']";

### 允许的文件大小
// 空的默认 2m
$fileSizeRate = 1048576; // 文件进制
$fileSize = empty($fileSize) ? 2 : $fileSize;
$fileSize = $fileSize * $fileSizeRate; // 单位为KB，转为M

### 外部样式
$wrapperClass = empty($wrapperClass) ? '' : $wrapperClass;
$wrapperClass = is_array($wrapperClass) ?
    implode(' ', (array)$wrapperClass) : $wrapperClass;

### 上传组件状态
$status = empty($status) ? '' : $status;

### 是否禁用
$disabled = empty($disabled) || !$disabled ? 'false' : $disabled;

// HTML
$template = <<<EOL

<div class="element-upload-wrapper $wrapperClass">
    <ul class="el-upload-list el-upload-list--picture-card">
        <transition-group name="el-zoom-in-center">
            <li tabindex="0" class="el-upload-list__item is-success el-list-enter-to"
                v-for="(item, key) in (isMultiple ? column : [column])" v-if="column" :key="key">
                <img :src="\$w.isImageUrl(item) ? item : '/images/backend/file.svg'"
                    :alt="item" class="el-upload-list__item-thumbnail">
                <a class="el-upload-list__item-name">
                    <i class="el-icon-document"></i>
                    {{item}}
                </a>
                <label class="el-upload-list__item-status-label">
                    <i class="el-icon-upload-success el-icon-check"></i>
                </label>
                <i class="el-icon-close"></i>
                <span class="el-upload-list__item-actions">
                    <span class="el-upload-list__item-preview" @click="handleSeeImage(item)"
                        v-if="canShowSeeIcon(item)">
                        <i class="el-icon-zoom-in"></i>
                    </span>
                    <span class="el-upload-list__item-down" @click="handleDownloadImage(item)">
                        <i class="el-icon-download"></i>
                    </span>
                    <span class="el-upload-list__item-delete" @click="handleRemoveItem(item)"
                        v-show="!isDisabled">
                        <i class="el-icon-delete"></i>
                    </span>
                </span>
            </li>
        </transition-group>
    </ul>
    <el-upload v-if="showUploader" title="点击上传图片" ref="uploader"
               list-type="picture-card"
               name="files"
               :show-file-list="false"
               :action="setting.uploadImgUrl"
               :data="{scenario: '$scenario'}"
               :multiple="$canMultiple"
               :on-success="handleThumbSuccess"
               :on-error="handleThumbError"
               :before-upload="handleThumbBefore"
               :on-change="handleChange"
               :disabled="isDisabled"
               :class="isHide ? 'el-upload-disabled' : ''"
               style="display: inline-block">
    
        <div @mouseleave="uploaderStatus = uploaderStatus=='uploading' ? 'uploading' : ''"
             @mouseenter="uploaderStatus = uploaderStatus == 'uploading' ? uploaderStatus : 'hover'"
             element-loading-text="" element-loading-spinner=" " class="w-h-100"
             element-loading-background="rgba(255, 255, 255, 0.8)"
             v-loading.lock="isDisabled">
    
            <i class="el-icon-plus avatar-uploader-icon"></i>
            
            <div class="el-loading-mask" v-show="uploaderStatus=='uploading'">
                <div class="el-loading-spinner">
                    <svg viewBox="25 25 50 50" class="circular">
                        <circle cx="50" cy="50" r="20" fill="none" class="path"></circle>
                    </svg>
                    <p class="el-loading-text">上传中...</p>
                </div>
            </div>
        </div>
    </el-upload>
    <el-image ref="previewImg" :src="previewingImg" :preview-src-list='previewingImgList' v-show="false"
                    style="width: 100px; height: 100px"></el-image>
</div>

EOL;

// 字段 默认类型
$columnType = $uploadNum > 1 ? 'Array' : 'String';
// 字段 默认值
$columnDefault = $uploadNum > 1 ? '[]' : "''";
// 是否操作多张图
$multipleVal = $uploadNum > 1 && $canMultiple == 'true' ? 'true' : 'false';
$js          = <<<EOL
Vue.component('{$componentName}', {
    template: `$template`,
    props: {
        column: { // 绑定字段
            type: $columnType,
            default: $columnDefault
        },
        scenario: { // 场景
            type: String,
            required: true
        },
        uploaderStatus: { // 是否上传中
            type: String
        },
        isDisabled: { // 是否禁用上传组件
            type: Boolean,
            default: true
        },
    },
    data: function () {
    
        return {
            setting: {
                uploadImgUrl: \$w.getApiUrl('{$uploadUrlKey}'), // 上传连接
                maxFileSize: $fileSize, // 文件大小
                fileTypeList: $fileTypes, // 文件类型
                defaultImgPath: '', // 默认图
            },
            showUploader: false, // 是否展示上传组件
            upload_variable: {},
            isMultiple: $multipleVal, // 是否操作多张
            numIsFull: false,      // 是否可上传数量饱和
            previewingImg: '',     // 当前查看中图片
            previewingImgList: '', // 当前查看中图片重塑列表， 为了修复每次查看都是第一张的问题
            isHide: false,         // 是否隐藏上传组件
        };
    },
    created: function() {
        var that = this;
        this.\$nextTick(function () {
            // 展示组件
            that.showUploader = true;
        });
    },
    methods: {
        /**
         * 图片上传 - 验证封面文件合法
         * @param \$file
         * @returns {boolean}
         */
        handleThumbBefore: function (\$file) {
        
            // 验证场景
            if (!this.scenario) {
            
                this.\$message({
                    type: 'error',
                    showClose: true,
                    message: '请完善场景字段[scenario]'
                });
                return false;
            }
            
            // 验证大小|文件大小
            if (\$file.size > this.setting.maxFileSize) {

                this.\$message({
                    type: 'error',
                    showClose: true,
                    message: '文件不得大于' + (this.setting.maxFileSize / 1024) / 1024 + 'M'
                });
                return false;
            }

            // 文件类型
            if (!\$w.in_array(\$file.type, this.setting.fileTypeList)) {

                this.\$message({
                    type: 'error',
                    showClose: true,
                    message: '文件类型不支持'
                });
                return false;
            }
            
            // 验证下数量 - 多选已满
            if (this.column && this.column.length >= $uploadNum && this.isMultiple) {
                this.\$message({
                    type: 'error',
                    showClose: true,
                    message: '最多上传{$uploadNum}张图片'
                });
                return false;
            }
            // 验证下数量 - 单选已满
            else if (!\$w.isEmpty(this.column) && !this.isMultiple) {
                this.\$message({
                    type: 'error',
                    showClose: true,
                    message: '最多上传{$uploadNum}张图片'
                });
                return false;
            }

            // 加载中
            this.changeStatus('uploading');
            return true;
        },
        /**
         * 图片上传 - 封面文件上传回调
         * @param \$response
         * @returns {*}
         */
        handleThumbSuccess: function (\$response) {

            var that = this;
            this.\$nextTick(function () {
                // 加载中
                that.changeStatus('');
            });

            // 上传失败提醒
            if (parseInt(\$response['no']) !== 200) {
                return this.\$message({
                    showClose: true,
                    type: 'error',
                    message: \$response['msg']
                });
            }
            // state失败
            if (\$response['data']['state'] === 'ERROR') {
                return this.\$message({
                    showClose: true,
                    type: 'error',
                    message: '上传失败'
                });
            }
            // 未登录
            if (parseInt(\$response['no']) === 401) {
                this.\$message({
                    showClose: true,
                    type: 'warning',
                    message: '登录超时，请重新登录'
                });

                // 几秒之后移除
                return setTimeout(function () {
                    window.parent.location.href = \$w.getPageUrl('login');
                }, 810);
            }
            
            // 多选 && 数据为空
            if (this.isMultiple && \$w.isEmpty(that.column)) this.column = [];
            
            if (this.isMultiple) this.column.push(\$response['data']['path']);
            else this.column = \$response['data']['path'];
            
            this.\$emit('update:column', this.column);
            this.\$parent.onFieldBlur();
            this.\$parent.onFieldChange();
            return true;
        },
        /**
         * 图片上传 - 文件上传失败回调
         * @param \$response
         * @returns {*}
         */
        handleThumbError: function (\$response) {

            this.\$message({
                type: 'error',
                showClose: true,
                message: '上传失败'
            });
            var that = this;
            this.\$nextTick(function () {
                // 状态
                that.changeStatus('');
            });

            return true;
        },
        /**
         * 图片上传 - 封面重新选择点击
         */
        handleRemoveItem: function (\$file) {
            
            // 默认第一个图
            \$file = \$file || (this.isMultiple ? \$w.array_first(this.column) : this.column);
            // 循环文件列表 移除相关图片
            if (this.isMultiple) for (var i in this.column) {
                if (!this.column.hasOwnProperty(i)) continue;
                if (this.column[i] !== \$file) continue;
                this.\$delete(this.column, i);
            } else if (\$file == this.column) {
                this.\$set(this, 'column', '');
            }
            
            // 当前状态为空
            this.changeStatus('refresh');
            
            // 更新
            this.\$emit('update:column', this.column);
        },
        /**
         * 是否展示查看图片ICON
         */
        canShowSeeIcon: function (\$file) {
            return \$w.isImageUrl(\$file);
        },
        /**
         * 是否展示下载文件ICON
         */
        canShowDownloadIcon: function (\$file) {
            return !\$w.isImageUrl(\$file);
        },
        /**
         * 查看图片按钮点击
         */
        handleSeeImage: function(\$file) {
            
            this.previewingImgList = [\$file];
            // 多图 需要添加其他图
            if (this.isMultiple) for (var i in this.column) {
                if (!this.column.hasOwnProperty(i)) continue;
                if (this.column[i] === \$file) continue;
                this.previewingImgList.push(this.column[i]);
            }
            
            this.previewingImg = \$file;
            // 当前状态
            this.changeStatus('see');
            
            var that = this;
            this.\$nextTick(function () {
            
                var dom = that.\$refs['previewImg'];
                // 点击查看
                if (dom) dom.clickHandler();
            });
        },
        /**
         * 下载文件按钮点击
         */
        handleDownloadImage: function (\$file) {
            window.location.href = \$file;
        },
        /**
         * 监测到文件列表改变
         */
        handleChange: function (\$file, \$fileList) {
            return true; // 已弃用
            for (var i in \$fileList) {
                if (!\$fileList.hasOwnProperty(i)) continue;
                // 未上传完成
                if (\$fileList[i]['status'] !== 'success') continue;
                // 成功200
                if (parseInt(\$fileList[i].response.no) === 200) continue;
                // 删除
                this.\$delete(\$fileList, i);
            }
        },
        /**
         * 修改上传状态
         */
        changeStatus: function (\$status) {
            // 当前状态
            this.\$emit('update:uploaderStatus', \$status);
            this.uploaderStatus = \$status;
        }
    },
    watch: {
        /**
         * 数量监测
         */
        column: {
            immediate: true, // 初始化触发
            handler: function (\$value) {
                // 数量 已满
                if (\$value && \$value.length >= $uploadNum && this.isMultiple) {
                    // 数量已满
                    this.numIsFull = true;
                    // 隐藏上传组件
                    this.isHide = true;
                }
                // 数量 已满
                else if (!\$w.isEmpty(\$value) && !this.isMultiple) {
                    
                    this.numIsFull = true;
                    // 隐藏上传组件
                    this.isHide = true;
                }
                // 数量 未满
                else {
                    
                    this.numIsFull = false;
                    // 不隐藏上传组件
                    this.isHide = false;
                }
            }
        },
        /**
         * 状态监测
         */
        uploaderStatus: function (\$value) {
          
            // 上传中
            if (\$value == 'uploading') {
                //  禁用
                this.disabled = true;
            }
        }
    },
    computed: {
        /**
         * 计算 文件列表
         */
        fileList: function () {
        
            var files = this.column;
            // 是空的 - 不分单选多选了，列表永远是数组
            if (\$w.isEmpty(files)) files = [];
            // 非空 - 不分单选多选了，列表永远是数组
            else if (typeof files !== 'object') files = [files];
            
            var fileList = [];
            for (var i in files) {
                if (!files.hasOwnProperty(i)) continue;
                fileList.push({name: files[i], url: files[i]});
            }
            return fileList;
        }
    }
})
EOL;

if (empty($this->params['uploader']['reg'])) $this->registerCss("
    .element-upload-wrapper .el-upload-disabled .el-upload {display: none}
    .el-upload-list .el-icon-zoom-in, .el-upload-list .el-icon-download, .el-upload-list .el-icon-delete {font-size: 20px;}
    .el-upload--picture-card {margin: 0 8px 8px 0;width: 148px;height: 148px;}
    .el-upload-list--picture-card .el-upload-list__item:first-child {margin-right: 0; margin-bottom: 0;}
");
if (empty($this->params['uploader']['reg']) && $multipleVal == 'true') $this->registerCss("
    .el-upload-list--picture-card .el-upload-list__item {margin-right: 0; margin-bottom: 0;}
");
if (empty($this->params['uploader']['reg'])) $this->registerJs($js);
// 已注册过
$this->params['uploader']['reg'] = true;

echo "<{$componentName} :column.sync='$column' scenario='$scenario' ref='$ref' :is-disabled='$disabled'" . (!empty($status) ? " :uploader-status.sync='$status'" : '') . "></{$componentName}>\n";
?>
